package com.liziguo.lzgfp.server.netty.handler;

import com.alibaba.fastjson.JSONObject;
import com.liziguo.lzgfp.server.dao.ForwardDao;
import com.liziguo.lzgfp.server.dao.UserDao;
import com.liziguo.lzgfp.server.domain.ForwardView;
import com.liziguo.lzgfp.server.entity.Forward;
import com.liziguo.lzgfp.server.entity.User;
import com.liziguo.lzgfp.server.netty.ForwardServer;
import com.liziguo.lzgfp.server.util.GlobalUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

//             ChannelHandlerAdapter       ChannelInboundHandlerAdapter        Inbound入站(不是栈)处理器
public class ServerHandler extends SimpleChannelInboundHandler<JSONObject> {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private final String aesKey;

    private List<ForwardServer> forwardServers;

    private boolean isValidated;//表示是否验证完毕。如果为false 30秒之后视为超时 自动断开 并打印一条日志

    private String key;

    public ServerHandler(String aesKey) {
        this.aesKey = aesKey;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, JSONObject jsonObject) throws Exception {
        logger.trace(jsonObject.toJSONString());
        ctx.fireChannelRead(jsonObject);
        switch (jsonObject.getString("type")) {
            case "client" -> {
                this.key = jsonObject.getString("key");
                synchronized (ServerHandler.class) {
                    if (key == null || key.isBlank()) {
                        logger.debug("key为空 连接中断");
                        isValidated = true;
                        ctx.close();
                        key = null;
                        return;
                    }
                    if (GlobalUtil.client.get(key) != null) {
                        logger.debug("客户端key:{} 已在线 连接中断", key);
                        final JSONObject msg = new JSONObject();
                        msg.put("type", "msg");
                        msg.put("message", "key:" + key + " 已在线 即将断开连接");
                        ctx.channel().writeAndFlush(msg);
                        isValidated = true;
                        key = null;//不设为null的话 触发channelInactive时会出bug
                        ctx.close();
                        return;
                    }
                    final User client = UserDao.selectByKey(key);
                    if (client == null) {
                        logger.debug("key:{} 不存在 连接中断", key);
                        isValidated = true;
                        ctx.close();
                        key = null;
                        return;
                    }
                    logger.info("接收到客户端连接 key:{} ip:{}", key, ctx.channel().remoteAddress());
                    final List<Forward> forwards = ForwardDao.selectByUserId(client.getId());
                    forwardServers = new ArrayList<>();
                    for (final Forward forward : forwards) {
                        try {
                            forwardServers.add(new ForwardServer(ctx.channel(), aesKey, key, forward.getServerport(), forward.getLocalhost(), forward.getLocalport()));
                        } catch (Exception e) {
                            logger.error("开启转发端口:{}失败 该端口可能被其他程序占用", forward.getServerport());
                            isValidated = true;
                            final JSONObject msg = new JSONObject();
                            msg.put("type", "msg");
                            msg.put("message", String.format("服务器打开%d端口失败 该端口可能被其他程序占用", forward.getServerport()));
                            ctx.channel().writeAndFlush(msg);
                            ctx.close();
                            return;
                        }
                    }
                    final JSONObject response = new JSONObject();
                    response.put("type", "router");
                    response.put("router", forwards.stream().map(ForwardView::create).collect(Collectors.toList()));
                    ctx.writeAndFlush(response);
                    isValidated = true;
                    GlobalUtil.client.put(key, ctx.channel());
                }
//                final JSONArray keys = jsonObject.getJSONArray("keys");
//                logger.info("接收到客户端连接 keys:{}", keys);
//                forwardServers = new ForwardServer[keys.size()];
//                final JSONArray router = new JSONArray();
//                final Ini ini = new Ini(new File("lzgfp-config.ini"));
//                for (int i = 0; i < forwardServers.length; i++) {
//                    final String key = keys.getString(i);
//                    final Profile.Section section = ini.get(key);
//                    if (section == null) {
//                        logger.error("key:{} 不存在", key);
//                        throw new RuntimeException(String.format("key:%s 不存在", key));
//                    }
//                    final int serverport = Integer.parseInt(section.get("serverport"));
//                    final String localhost = section.get("localhost");
//                    final int localport = Integer.parseInt(section.get("localport"));
//                    forwardServers[i] = new ForwardServer(ctx.channel(), key, serverport, localhost, localport);
//                    My.client.put(key, ctx.channel());
//                    final JSONObject server = new JSONObject();
//                    server.put("key", key);
//                    server.put("serverport", serverport);
//                    server.put("localhost", localhost);
//                    server.put("localport", localport);
//                    router.add(server);
//                }
//                final JSONObject response = new JSONObject();
//                response.put("type", "router");
//                response.put("router", router);
//                ctx.writeAndFlush(response);
//                isValid = true;
            }
//            case "forward" -> {
//                final String forKey = jsonObject.getString("forKey");
//                final Channel channel = GlobalUtil.forward.remove(forKey);
//                if (channel == null) {
//                    ctx.close();
//                    logger.error("forKey:{} 不存在", forKey);
//                    return;
//                }
//                final int len = ctx.pipeline().toMap().size();
//                for (int i = 0; i < len; i++) {
//                    ctx.pipeline().removeLast();
//                }
//                ctx.pipeline().addLast(new ForWardHandler(channel));
//                channel.pipeline().addLast(new ForWardHandler(ctx.channel()));
//                logger.info("开启{}和{}转发成功", ctx.channel().remoteAddress(), channel.remoteAddress());
//                isValidated = true;//由于监听事件已开启就算当前Handler被移除也会触发
//            }

        }

    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof final IdleStateEvent event) {
            if (event.state() == IdleState.READER_IDLE) {
                // 在规定时间内没有收到客户端的上行数据, 主动断开连接
                ctx.disconnect();//TCP调用close UDP调用disconnect
                logger.info("关闭了一个没有心跳的客户端连接{}", ctx.channel());
            } else if (event.state() == IdleState.WRITER_IDLE) {
                final JSONObject jsonObject = new JSONObject();
                jsonObject.put("type", "ping");
                jsonObject.put("ping", LocalDateTime.now());
                ctx.channel().writeAndFlush(jsonObject);
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.channel().eventLoop().schedule(() -> {
            if (!isValidated) {
                ctx.close();
                logger.debug("断开了一个无效连接{}", ctx.channel().remoteAddress());
            }
        }, 5, TimeUnit.SECONDS);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        if (key != null && !key.isBlank()) {
            GlobalUtil.client.remove(key);
            logger.info("一个客户端断开了连接key:{} {}", key, ctx.channel());
        }
        if (forwardServers != null) {
            for (ForwardServer forwardServer : forwardServers) {
                forwardServer.close();
            }
        }

        ctx.fireChannelInactive();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error(cause.getMessage());
        cause.printStackTrace();
        ctx.close();
    }

}